#include "arch/mips/MIPSVBasicBlockBuilder.h"
#include "crossbit/InstructionReorderFilter.h"
#include "crossbit/VBlock.h"
#include "crossbit/UTIL.h"

using namespace crossbit;

MIPSVBasicBlockBuilder::MIPSVBasicBlockBuilder()
{
				UTIL::XTMemset( usedRegTable, 0, MAXREGS );
				UTIL::XTMemset( luIndex, 0, MAXREGS );
}

void MIPSVBasicBlockBuilder::getReady(XTMemAddr pc)
{
			VBasicBlockBuilder::getReady(pc);
			UTIL::XTMemset( usedRegTable, 0, MAXREGS );
			UTIL::XTMemset( luIndex, 0, MAXREGS );
}

void MIPSVBasicBlockBuilder::add(VInst *inst)
{
				Opcode opcode = inst->getOpcode();
				Opkind opkind = inst->getOpkind();

				// We have to bail out if a SYSCALL instruction is met
				// to do the system call emulation since SimpleScalar
				// is based on different syscall set than linux.

				if( (opcode == OP_GET) && (inst->getOperand(1).reg == inst->getOperand(2).reg))
				{
								XTInt32 temp = inst->getOperand(1).reg;
								if( usedRegTable[temp] == 0 )
								{
												usedRegTable[temp] |= REGUSED;
								}
								else
								{
												return;
								}
				}
				else if( (opcode == OP_PUT) && (inst->getOperand(1).reg == inst->getOperand(2).reg) )
				{

								//record the latest PUT inst of reg
								XTInt32 i = inst->getOperand(2).reg;
								usedRegTable[i] |= REGDEF;
								if( luIndex[i] != 0 )
												bb_vblock->setVbIlist(luIndex[i], NULL);
								luIndex[i] = bb_vblock->size(); 

								//return;
				}
				else if ( opcode == OP_SYSCALL			||
												opkind == OPK_CONTROLTRANSFER	||
												opcode == OP_HALT)
				{
								bb_end = true;
				}

				bb_vblock->push_back(inst);
}

VBlock* MIPSVBasicBlockBuilder::wrapUp(XTMemAddr pc)
{
				VBlock::vb_iterator it = bb_vblock->begin();
				while( it != bb_vblock->end() )
				{
								if( *it == NULL )
								{
												it = bb_vblock->erase(it);
								}
								else
												++it;
				}
				/*
				InstructionReorderFilter filet;
				filet.run( bb_vblock );
				
				*/
				
				//Added by suntingtao , remove the unnecessary 'MOV' intermediate instrution
				it = bb_vblock -> begin();
				VBlock::vb_iterator tmp;
				while( it != bb_vblock -> end() ){
					   if( (*it) -> getOpcode() == OP_MOV && ((*it) -> getOperand(2).reg == 34 || (*it) -> getOperand(2).reg == 35 )){
							// MOV src , dst
							XTRegNum src = (*it) -> getOperand(1).reg;
							XTRegNum dst = (*it) -> getOperand(2).reg;
						    tmp = it;
							tmp++;
							bool removable = true;
							while( removable && tmp != bb_vblock -> end() ){
								   XTInt32 n = (*tmp) -> getOperandNum();
								   Operand opr;
								   for( XTInt32 i = 1 ; i <= n ; i++ ){
								   		 opr = (*tmp) -> getOperand(i);
								         if( opr.type == Operand::VREG_DEF && (opr.reg == src || opr.reg == dst))
										 removable = false;
                                         
								   }	
								   tmp++;
							}
	
							if( removable ){
								tmp = it;
								tmp++;
								while( tmp != bb_vblock -> end() ){
									XTInt32 n = (*tmp) -> getOperandNum();
									for( XTInt32 i = 1 ; i <= n ; i++ ){
										Operand opr = (*tmp) -> getOperand(i);
										if( opr.type == Operand::VREG_USE && opr.reg == dst ){
											    opr.reg = src; 	
												(*tmp) -> setOperand( i , opr);
										}
                                    }
									tmp++;
								}
								it = bb_vblock -> erase(it);
							}else
								++it;
					}else
						++it;
				}			
			    // -->	
//	*/			
                                         
				return VBasicBlockBuilder::wrapUp(pc);
}
